//游戏类
const Player = require("../object/player");
const Constants = require("../../shared/contants");
const {distanceTo} =require("../utils")

class Game {
  constructor() {
    //保存玩家的socket信息
    this.sockets = {};
    //保存玩家的游戏对象信息
    this.players = {};
    //子弹
    this.bullets = [];
    //最后一次执行时间
    this.lastUpdateTime = Date.now();
    //是否发送给前端数据，这里将每两帧发送一次数据
    this.shouldSendUpdate = false;
    //游戏更新
    setInterval(this.update.bind(this), 1000 / 60);
  }

  update() {
    const now = Date.now();
    // 现在的时间减去上次执行完毕的时间得到中间间隔的时间
    const dt = (now - this.lastUpdateTime) / 1000;
    this.lastUpdateTime = now;

    //如果子弹飞出地图或到达人物身上，就过滤掉
    this.bullets = this.bullets.filter((item) => !item.isOver);
    this.bullets.map((bullet) => {
      bullet.update(dt);
    });

    this.collisions(Object.values(this.players), this.bullets);

    // 更新玩家人物
    Object.keys(this.players).map((playerID) => {
      const player = this.players[playerID];

      //添加子弹
      const bullet = player.update(dt);
      if (bullet) {
        this.bullets.push(bullet);
      }
    });

    Object.keys(this.sockets).map((playerID) => {
      const socket = this.sockets[playerID];
      const player = this.players[playerID];
      // 如果玩家的血量低于等于0就告诉他游戏结束，并将其移除游戏
      if (player.hp <= 0) {
        socket.emit(Constants.MSG_TYPES.GAME_OVER);
        this.disconnect(socket);
      }
    });

    //是否更新
    if (this.shouldSendUpdate) {
      Object.keys(this.sockets).map((playerID) => {
        const socket = this.sockets[playerID];
        const player = this.players[playerID];

        socket.emit(Constants.MSG_TYPES.UPDATE, this.createUpdate(player));
      });
      this.shouldSendUpdate = false;
    } else {
      this.shouldSendUpdate = true;
    }
  }

  createUpdate(player) {
    //其他玩家
    const otherPlayer = Object.values(this.players).filter((p) => p !== player);

    return {
      t: Date.now(),
      me: player.serializeForUpdate(),
      others: otherPlayer,
      // 子弹
      bullets: this.bullets.map((bullet) => bullet.serializeForUpdate()),
    };
  }

  //玩家加入游戏
  joinGame(socket, username) {
    this.sockets[socket.id] = socket;

    //玩家位置随机生成
    const x = (Math.random() * 0.5 + 0.25) * Constants.MAP_SIZE;
    const y = (Math.random() * 0.5 + 0.25) * Constants.MAP_SIZE;

    this.players[socket.id] = new Player({
      id: socket.id,
      username,
      x,
      y,
      w: Constants.PLAYER.RADUIS,
      h: Constants.PLAYER.RADUIS,
    });
  }

  handleInput(socket, item) {
    const player = this.players[socket.id];
    if (player) {
      let data = item.action.split("-");
      let type = data[0];
      let value = data[1];
      switch (type) {
        case "move":
          player.move[value] =
            typeof item.data === "boolean" ? (item.data ? 1 : -1) : 0;
          break;
        case "dir":
          player.fireMouseDir = item.data;
          break;
        case "bullet":
          player.fire = item.data;
          break;
      }
    }
  }

  collisions(players, bullets) {
    for (let i = 0; i < bullets.length; i++) {
      for (let j = 0; j < players.length; j++) {
        let bullet = bullets[i];
        let player = players[j];
        //distanceTo是通过勾股定理判断物体与自己的距离
        if (
          bullet.parentId !== player.id &&
          distanceTo(player, bullet) <=
            Constants.PLAYER.RADUIS + Constants.BULLET.RADUIS
        ) {
          bullet.isOver = true;
          //减血
          player.takeBulletDamage(bullet.power);
          if (player.hp <= 0) {
            this.players[bullet.parentId].score++;
          }

          break;
        }
      }
    }
  }

  //玩家断开游戏连接
  disconnect(socket) {
    delete this.sockets[socket.id];
    delete this.players[socket.id];
  }
}

module.exports = Game;
